<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Vue2移动端PDF预览 - 单页面演示</title>

    <!-- Vue.js -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>

    <!-- Element UI CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.13/lib/theme-chalk/index.css">

    <!-- Element UI JS -->
    <script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.13/lib/index.js"></script>

    <!-- IE兼容性 -->
    <!--[if lt IE 11]>
    <script src="https://cdn.jsdelivr.net/npm/promise-polyfill@8/dist/polyfill.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/whatwg-fetch@3.6.2/dist/fetch.umd.js"></script>
    <![endif]-->

    <style>
        /* 全局样式 */
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        html, body {
            height: 100%;
            font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', '微软雅黑', Arial, sans-serif;
        }

        #app {
            height: 100vh;
        }

        /* 移动端优化 */
        * {
            -webkit-tap-highlight-color: transparent;
            -webkit-touch-callout: none;
            -webkit-user-select: none;
            user-select: none;
        }

        p, span, div, h1, h2, h3, h4, h5, h6 {
            -webkit-user-select: text;
            user-select: text;
        }

        button, a, [role="button"] {
            -webkit-tap-highlight-color: rgba(0, 0, 0, 0.1);
        }

        body {
            -webkit-font-smoothing: antialiased;
            -moz-osx-font-smoothing: grayscale;
        }
    </style>
</head>
<body>
<div id="app">
    <!-- 这里将加载PdfViewer组件 -->
</div>

<script>
    // 注册Element UI
    Vue.use(ELEMENT);

    // 创建Vue实例
    new Vue({
        el: '#app',
        template: `
                <div>
                    <pdf-viewer></pdf-viewer>
                </div>
            `,
        components: {
            'pdf-viewer': {
                template: `
                        <div id="app">
                            <!-- 头部 -->
                            <div class="header">
                                <h1>PDF文档预览</h1>
                            </div>

                            <!-- 主体内容 -->
                            <div class="main-content">
                                <!-- 左侧菜单 -->
                                <div class="menu-sidebar">
                                    <div class="menu-container">
                                        <div
                                            v-for="(menu, index) in menuList"
                                            :key="index"
                                            class="menu-item"
                                        >
                                            <!-- 一级菜单 -->
                                            <div
                                                class="menu-level-1"
                                                :class="{ 'active': menu.expanded }"
                                                @click="toggleMenu(index)"
                                            >
                                                <i class="el-icon-folder" v-if="!menu.expanded"></i>
                                                <i class="el-icon-folder-opened" v-else></i>
                                                <span>{{ menu.title }}</span>
                                                <i class="el-icon-arrow-down" :class="{ 'rotated': menu.expanded }"></i>
                                            </div>

                                            <!-- 二级菜单 -->
                                            <transition name="submenu">
                                                <div v-show="menu.expanded" class="submenu">
                                                    <div
                                                        v-for="(subItem, subIndex) in menu.children"
                                                        :key="subIndex"
                                                        class="menu-level-2"
                                                        :class="{ 'active': selectedSubMenu === subItem.id }"
                                                        @click="selectSubMenu(subItem)"
                                                    >
                                                        <i class="el-icon-document"></i>
                                                        <span>{{ subItem.title }}</span>
                                                    </div>
                                                </div>
                                            </transition>
                                        </div>
                                    </div>
                                </div>

                                <!-- 右侧PDF预览区域 -->
                                <div class="pdf-container">
                                    <div v-if="!currentPdfUrl" class="empty-state">
                                        <i class="el-icon-document"></i>
                                        <p>请选择左侧菜单中的文档进行预览</p>
                                    </div>

                                    <div v-else class="pdf-viewer">
                                        <!-- PDF加载状态 -->
                                        <div v-if="loading" class="loading">
                                            <div class="loading-spinner"></div>
                                            <p>正在加载PDF文档...</p>
                                        </div>

                                        <!-- PDF预览 -->
                                        <div v-else class="pdf-content">
                                            <div class="pdf-toolbar">
                                                <button class="btn" @click="prevPage" :disabled="currentPage <= 1">
                                                    <i class="el-icon-arrow-left"></i> 上一页
                                                </button>
                                                <span class="page-info">{{ currentPage }} / {{ totalPages }}</span>
                                                <button class="btn" @click="nextPage" :disabled="currentPage >= totalPages">
                                                    下一页 <i class="el-icon-arrow-right"></i>
                                                </button>
                                                <button class="btn" @click="zoomIn">
                                                    <i class="el-icon-zoom-in"></i>
                                                </button>
                                                <button class="btn" @click="zoomOut">
                                                    <i class="el-icon-zoom-out"></i>
                                                </button>
                                                <button class="btn" @click="downloadPdf">
                                                    <i class="el-icon-download"></i> 下载
                                                </button>
                                            </div>

                                            <div class="pdf-canvas-container" ref="pdfContainer">
                                                <canvas ref="pdfCanvas"></canvas>
                                            </div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                    `,
                data() {
                    return {
                        menuList: [
                            {
                                title: '技术文档',
                                expanded: true,
                                children: [
                                    { id: 'tech-1', title: 'Vue.js开发指南', pdfUrl: '/pdf/java.pdf' },
                                    { id: 'tech-2', title: 'ElementUI使用手册', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
                                    { id: 'tech-3', title: '移动端适配方案', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' }
                                ]
                            },
                            {
                                title: '产品文档',
                                expanded: false,
                                children: [
                                    { id: 'product-1', title: '产品需求文档', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
                                    { id: 'product-2', title: '用户使用手册', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
                                    { id: 'product-3', title: 'API接口文档', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' }
                                ]
                            },
                            {
                                title: '项目文档',
                                expanded: false,
                                children: [
                                    { id: 'project-1', title: '项目计划书', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
                                    { id: 'project-2', title: '项目总结报告', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' },
                                    { id: 'project-3', title: '技术架构文档', pdfUrl: 'https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf' }
                                ]
                            }
                        ],
                        selectedSubMenu: null,
                        currentPdfUrl: null,
                        loading: false,
                        pdfDoc: null,
                        currentPage: 1,
                        totalPages: 0,
                        scale: 1.0
                    }
                },
                mounted() {
                    this.loadPdfJs()
                },
                methods: {
                    async loadPdfJs() {
                        if (typeof window.pdfjsLib === 'undefined') {
                            const script = document.createElement('script')
                            script.src = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.min.js'
                            script.onload = () => {
                                window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdn.jsdelivr.net/npm/pdfjs-dist@3.11.174/build/pdf.worker.min.js'
                            }
                            document.head.appendChild(script)
                        }
                    },

                    toggleMenu(index) {
                        this.menuList[index].expanded = !this.menuList[index].expanded
                    },

                    async selectSubMenu(subItem) {
                        this.selectedSubMenu = subItem.id
                        this.currentPdfUrl = subItem.pdfUrl
                        this.loading = true

                        try {
                            await this.loadPdf(subItem.pdfUrl)
                        } catch (error) {
                            console.error('加载PDF失败:', error)
                            this.showMessage('加载PDF文档失败，请稍后重试', 'error')
                        } finally {
                            this.loading = false
                        }
                    },

                    async loadPdf(pdfUrl) {
                        try {
                            while (typeof window.pdfjsLib === 'undefined') {
                                await new Promise(resolve => setTimeout(resolve, 100))
                            }

                            const loadingTask = window.pdfjsLib.getDocument(pdfUrl)
                            this.pdfDoc = await loadingTask.promise
                            this.totalPages = this.pdfDoc.numPages
                            this.currentPage = 1
                            await this.renderPage()
                        } catch (error) {
                            console.error('PDF加载失败:', error)
                            throw error
                        }
                    },

                    async renderPage() {
                        if (!this.pdfDoc) return

                        try {
                            const page = await this.pdfDoc.getPage(this.currentPage)
                            const canvas = this.$refs.pdfCanvas
                            const context = canvas.getContext('2d')

                            const viewport = page.getViewport({ scale: this.scale })
                            canvas.height = viewport.height
                            canvas.width = viewport.width

                            const renderContext = {
                                canvasContext: context,
                                viewport: viewport
                            }

                            await page.render(renderContext).promise
                        } catch (error) {
                            console.error('页面渲染失败:', error)
                            this.showMessage('页面渲染失败', 'error')
                        }
                    },

                    async prevPage() {
                        if (this.currentPage > 1) {
                            this.currentPage--
                            await this.renderPage()
                        }
                    },

                    async nextPage() {
                        if (this.currentPage < this.totalPages) {
                            this.currentPage++
                            await this.renderPage()
                        }
                    },

                    async zoomIn() {
                        this.scale = Math.min(this.scale + 0.2, 3.0)
                        await this.renderPage()
                    },

                    async zoomOut() {
                        this.scale = Math.max(this.scale - 0.2, 0.5)
                        await this.renderPage()
                    },

                    downloadPdf() {
                        if (this.currentPdfUrl) {
                            const link = document.createElement('a')
                            link.href = this.currentPdfUrl
                            link.download = 'document.pdf'
                            link.click()
                        }
                    },

                    showMessage(message, type = 'info') {
                        const messageEl = document.createElement('div')
                        messageEl.className = `message message-${type}`
                        messageEl.textContent = message

                        document.body.appendChild(messageEl)

                        setTimeout(() => {
                            if (messageEl.parentNode) {
                                messageEl.parentNode.removeChild(messageEl)
                            }
                        }, 3000)
                    }
                }
            }
        }
    });
</script>

<style>
    /* 组件样式 */
    #app {
        height: 100vh;
        display: flex;
        flex-direction: column;
        background-color: #f5f5f5;
        -webkit-font-smoothing: antialiased;
        -moz-osx-font-smoothing: grayscale;
    }

    .header {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        color: white;
        padding: 1rem;
        text-align: center;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
    }

    .header h1 {
        font-size: 1.5rem;
        font-weight: 500;
        margin: 0;
    }

    .main-content {
        flex: 1;
        display: flex;
        overflow: hidden;
    }

    .menu-sidebar {
        width: 280px;
        background: white;
        border-right: 1px solid #e4e7ed;
        overflow-y: auto;
    }

    .menu-container {
        padding: 1rem 0;
    }

    .menu-item {
        margin-bottom: 0.5rem;
    }

    .menu-level-1 {
        display: flex;
        align-items: center;
        padding: 0.75rem 1rem;
        cursor: pointer;
        transition: all 0.3s ease;
        border-left: 3px solid transparent;
    }

    .menu-level-1:hover {
        background-color: #f5f7fa;
    }

    .menu-level-1.active {
        background-color: #ecf5ff;
        border-left-color: #409eff;
        color: #409eff;
    }

    .menu-level-1 i {
        margin-right: 0.5rem;
        font-size: 1.1rem;
    }

    .menu-level-1 .el-icon-arrow-down {
        margin-left: auto;
        transition: transform 0.3s ease;
    }

    .menu-level-1 .el-icon-arrow-down.rotated {
        transform: rotate(180deg);
    }

    .submenu {
        background-color: #fafafa;
        border-left: 3px solid #e4e7ed;
        margin-left: 1rem;
    }

    .menu-level-2 {
        display: flex;
        align-items: center;
        padding: 0.5rem 1rem;
        cursor: pointer;
        transition: all 0.3s ease;
        font-size: 0.9rem;
    }

    .menu-level-2:hover {
        background-color: #f0f9ff;
    }

    .menu-level-2.active {
        background-color: #e6f7ff;
        color: #1890ff;
    }

    .menu-level-2 i {
        margin-right: 0.5rem;
        font-size: 1rem;
    }

    .submenu-enter-active, .submenu-leave-active {
        transition: all 0.3s ease;
    }

    .submenu-enter, .submenu-leave-to {
        opacity: 0;
        transform: translateY(-10px);
    }

    .pdf-container {
        flex: 1;
        background: white;
        display: flex;
        flex-direction: column;
    }

    .empty-state {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        color: #909399;
    }

    .empty-state i {
        font-size: 4rem;
        margin-bottom: 1rem;
    }

    .empty-state p {
        font-size: 1.1rem;
    }

    .pdf-viewer {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    .loading {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        color: #909399;
    }

    .loading-spinner {
        width: 40px;
        height: 40px;
        border: 4px solid #f3f3f3;
        border-top: 4px solid #409eff;
        border-radius: 50%;
        animation: spin 1s linear infinite;
        margin-bottom: 1rem;
    }

    @keyframes spin {
        0% { transform: rotate(0deg); }
        100% { transform: rotate(360deg); }
    }

    .loading p {
        margin-top: 1rem;
        font-size: 1rem;
    }

    .pdf-content {
        flex: 1;
        display: flex;
        flex-direction: column;
        overflow: hidden;
    }

    .pdf-toolbar {
        padding: 0.75rem;
        background: #f8f9fa;
        border-bottom: 1px solid #e4e7ed;
        display: flex;
        align-items: center;
        gap: 0.5rem;
        flex-wrap: wrap;
    }

    .btn {
        padding: 0.5rem 1rem;
        border: 1px solid #dcdfe6;
        background: white;
        color: #606266;
        border-radius: 4px;
        cursor: pointer;
        font-size: 0.875rem;
        transition: all 0.3s ease;
        display: flex;
        align-items: center;
        gap: 0.25rem;
    }

    .btn:hover:not(:disabled) {
        background: #f5f7fa;
        border-color: #c0c4cc;
    }

    .btn:disabled {
        opacity: 0.6;
        cursor: not-allowed;
    }

    .btn i {
        font-size: 0.875rem;
    }

    .page-info {
        margin: 0 1rem;
        font-weight: 500;
        color: #606266;
    }

    .pdf-canvas-container {
        flex: 1;
        overflow: auto;
        padding: 1rem;
        display: flex;
        justify-content: center;
        background-color: #f5f5f5;
    }

    .pdf-canvas-container canvas {
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
        background: white;
    }

    .message {
        position: fixed;
        top: 20px;
        right: 20px;
        padding: 0.75rem 1rem;
        border-radius: 4px;
        color: white;
        font-size: 0.875rem;
        z-index: 9999;
        animation: slideIn 0.3s ease;
    }

    .message-info {
        background-color: #409eff;
    }

    .message-error {
        background-color: #f56c6c;
    }

    .message-success {
        background-color: #67c23a;
    }

    @keyframes slideIn {
        from {
            transform: translateX(100%);
            opacity: 0;
        }
        to {
            transform: translateX(0);
            opacity: 1;
        }
    }

    /* 移动端适配 */
    @media screen and (max-width: 768px) {
        .main-content {
            flex-direction: column;
        }

        .menu-sidebar {
            width: 100%;
            max-height: 200px;
            border-right: none;
            border-bottom: 1px solid #e4e7ed;
        }

        .header h1 {
            font-size: 1.2rem;
        }

        .pdf-toolbar {
            padding: 0.5rem;
            gap: 0.25rem;
        }

        .btn {
            padding: 0.25rem 0.5rem;
            font-size: 0.8rem;
        }

        .page-info {
            margin: 0 0.5rem;
            font-size: 0.9rem;
        }

        .pdf-canvas-container {
            padding: 0.5rem;
        }
    }

    /* 滚动条样式 */
    ::-webkit-scrollbar {
        width: 6px;
        height: 6px;
    }

    ::-webkit-scrollbar-track {
        background: #f1f1f1;
        border-radius: 3px;
    }

    ::-webkit-scrollbar-thumb {
        background: #c1c1c1;
        border-radius: 3px;
    }

    ::-webkit-scrollbar-thumb:hover {
        background: #a8a8a8;
    }
</style>
</body>
</html>